<?php
namespace app\index\controller;

use think\Controller;
use QL\QueryList;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use think\Request;

class Comments extends Controller
{
    //
    private $spreadsheet = null;
    //
    private $sheet = null;

    //
    private $filePath = '';
    private $fileName = '';

    private $notRec = 0;

    private $redis = null;
    private $queryKey = 'comments_fetch_result_list_ley_';

    public function __construct(Request $request = null)
    {
        parent::__construct($request);

        $this->filePath = RUNTIME_PATH . "user-data/";

        $this->check_folder($this->filePath);

        $this->redis = new \Redis;
        $this->redis->connect(config('redis.host'), config('redis.port'));

    }

    public function add_list(){
        $this->queryKey .= input('param.fd');

        for($i = 0; $i < 10; $i ++) {
            $subRules = array(
                0,
                1,
                'title' => 'test',
                'starts' => '3',
                'author' => 'chenishr',
                'author_url' => 'https://blog.chenishr.com/',
                'comment' => 'not ok',
                'comment_url' => 'sd',
                'date' => date('Y-m-d H:i:s'),
            );
            $this->redis->lpush($this->queryKey,json_encode($subRules));
            sleep(1);
        }

        // 成功
        $resJson['ack'] = 0;
        $resJson['url'] = url('/index/Comments/download_file',['fileName' => str_replace($this->filePath,'',$this->fileName)]);

        echo json_encode($resJson);
    }

    public function download_file($fileName = ''){
        //$fileName = 'comments-prod-1526568541.xlsx';
        $this->fileName = $this->filePath . $fileName;

        try {
            $this->spreadsheet = IOFactory::load($this->fileName);
        }catch (\Exception $e){
            die($e->getMessage());
        }

        $this->sheet = $this->spreadsheet->getActiveSheet();

        // We'll be outputting an excel file
        header('Content-type: application/vnd.ms-excel');

        // It will be called file.xls
        header('Content-Disposition: attachment; filename="' . $fileName . '"');

        // 保存 excel
        $writer = new Xlsx($this->spreadsheet);
        $writer->save('php://output');
    }

    /**
     * 循环变量所有页面
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    public function get_comments(){
        $url = input('param.url');
        $date = input('param.date');

        $url = $this->_get_url(1);
        $date = '2018-01-01';

        if('' == $url  ||  '' == $date){
            $data = [
                'wsHost' => 'ws://' . $_SERVER['SERVER_NAME'] . ':9501',
            ];
            return view('get-comments',$data);
        }

        $ajax = false;
        $fd = input('param.fd');
        if('' != $fd) {
            $this->queryKey .= $fd;
            $ajax = true;
        }

        $res = $this->fetch_comments($url,$date,$ajax);

        if(true !== $res){
            $resJson['ack'] = 1;
            $resJson['msg'] = $res;
        }else{
            // 成功
            $resJson['ack'] = 0;
            $resJson['msg'] = url('/index/Comments/download_file',['fileName' => str_replace($this->filePath,'',$this->fileName)]);
        }

        echo json_encode($resJson);
    }
    public function fetch_comments($url = '',$date,$ajax = false){
        ini_set('memory_limit', '512M');
        set_time_limit(0);
        //ob_start(); //打开输出缓冲区

        // 验证 URL 是否正确
        if(false === strpos($url,'reviewerType=all_reviews')){
            return ' 链接地址错误 !';
        }

        $page = 1;

        // 计数器
        $this->_init(time());

        $reg = '/(pageNumber=)\d+/';

        try{
            do{
                $url = preg_replace($reg,'${1}' . $page,$url);
                if(!$ajax) {
                    echo "downloading page " . $page . "<br />";
                }
                $page ++;

            }while($this->_get_comments($url,($page - 1),$date,$ajax));
        }catch (\Exception $e){
            return $e->getMessage();
        }

        $this->_save_file();

        return true;
    }

    private function _get_url($prod){
        $url = '';

        switch($prod){
            case 1:
                $url = "https://www.amazon.com/Transmitter-Otium-Bluetooth-Wireless-Modulator/product-reviews/B01DZKERVY/ref=cm_cr_othr_d_show_all?ie=UTF8&reviewerType=all_reviews&pageNumber=1&sortBy=recent";
        }

        return $url;
    }

    /**
     * 抓取评论信息，保存到内存
     * @param $url
     * @param $page
     * @return bool
     */
    private function _get_comments($url,$page,$date,$ajax = false){
        echo "fetching : " . $url . "\n";
        $index = ($page - 1) * 10 - $this->notRec;
        $html = $this->_getSslPage($url);
        $rules = array(
            'comments' => array(' .review','html'),
        );
        $data = QueryList::html($html) ->rules($rules) ->query() ->getData();
        unset($html);

        // 抓取失败
        if(!$data || empty($data[0]['comments'])){
            return false;
        }

        $parseUrl = parse_url($url);

        foreach($data as $val){
            $subRules = array(
                'title' => array('.review-title','text'),
                'starts' => array('.review-rating > .a-icon-alt','text'),
                'author' => array('.author','text'),
                'author_url' => array('.author','href'),
                'comment' => array('.review-text','text'),
                'comment_url' => array('.review-title','href'),
                'date' => array('.review-date','text'),
            );

            $comment = QueryList::html($val['comments'])->rules($subRules)->query()->getData();
            $tmpData = $comment->all()[0];

            // 超出时间段的则返回
            if(strtotime(str_replace('on','',$tmpData['date'])) < strtotime($date)){
                return false;
            }

            // 排除 4 星 5 星
            if(strpos($tmpData['starts'],'5.0 out') !== false
                || strpos($tmpData['starts'],'4.0 out') !== false){
                $this->notRec ++;
                continue;
            }

            // 补全 url
            $tmpData['author_url'] = $parseUrl['scheme'] . "://" . $parseUrl['host'] . $tmpData['author_url'];
            $tmpData['comment_url'] = $parseUrl['scheme'] . "://" . $parseUrl['host'] . $tmpData['comment_url'];


            $index ++;
            //array_unshift($tmpData,['page' => $page]);
            //array_unshift($tmpData,['index' => $index]);

            $appendData = [
                'index' => $index,
                'page' => $page,
            ];
            $tmpData = array_merge($appendData,$tmpData);

            $this->redis->lpush($this->queryKey,json_encode($tmpData));

            // 保存到 excel
            if($ajax) {
                $this->sheet->fromArray(array_values($tmpData), NULL, 'A' . (1 + $index));
            }else{
                echo "<pre>";
                print_r($tmpData);
                echo "</pre>";
            }
            unset($tmpData);
            unset($comment);

        }

        unset($data);

        return true;
    }

    /**
     * 执行网络请求
     * @param $url
     * @return mixed
     */
    private function _getSslPage($url) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_REFERER, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        $result = curl_exec($ch);
        curl_close($ch);
        return $result;
    }

    /**
     * 对象销毁时调用的函数，确保数据已经保存
     */
    public function __destruct() {
        if(isset($this->spreadsheet)){
            $this->_save_file();
        }
    }

    /**
     * 文件初始化
     */
    private function _init($prod){
        $this->fileName =$this->filePath . "comments-prod-{$prod}.xlsx";

        //
        if(!file_exists($this->fileName)){
            $this->_init_file();
        }

        $this->_load_file();
    }

    /**
     * 加载文件
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     */
    private function _load_file(){
        $this->spreadsheet = IOFactory::load($this->fileName);
        $this->sheet = $this->spreadsheet->getActiveSheet();
    }

    /**
     * 保存文件，同时销毁变量
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    private function _save_file(){
        // 保存 excel
        $writer = new Xlsx($this->spreadsheet);
        $writer->save($this->fileName);
        unset($this->spreadsheet);
        unset($this->sheet);
        unset($writer);
    }

    /**
     * 文件初始化
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     */
    private function _init_file(){
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->fromArray(['id','page','title','star','author','author_url','comment','comment_url','date']);
        $writer = new Xlsx($spreadsheet);
        $writer->save($this->fileName);
        unset($spreadsheet);
        unset($sheet);
        unset($writer);
    }

    private function check_folder($path)
    {
        if(!is_readable($path))
        {
            is_file($path) or mkdir($path,0755);
        }
    }
}
